#ifndef __INOTIFYD_H_
#define __INOTIFYD_H_

#define BUFFER_SIZE 16384

struct dirname_t {
	char *name;
	int length;
	int parent;
};

struct dirhash_t {
	int idx;
	dirname_t* obj;
	dirhash_t* next;
};

struct dirmove_t {
	__u32 cookie;
	inotify_event *from;
	inotify_event *to;
	char *fromName;
	char *toName;
	dirmove_t* next;
};

class MountPoint {
	public:
		bool valid;
		char *mountPointName;
		char *deviceName;
		int pid;
		pthread_t watchThread;
		pthread_t scanThread;

		MountPoint(char* device, char* mount);
		virtual ~MountPoint();
		void start();

		void watchFileDescriptor();
		void scanMount();
	private:
		int st_dev;
		int fd;
		int maxWD;
		dirhash_t **directoryNames;
		const static int hash = 32749;

		int directoryEvent(inotify_event *event);
		void scanDirectory(char *path, char *name, int parent, int depth);
		char* getDirectoryName(int idx);
		char* getFileName(inotify_event *event);
		void recurseName(int idx, char *buffer, int &cpos, int &size);
		dirname_t* getDirEntry(int idx);
		void setDirEntry(int idx, int parent, int length, char* name);
		bool removeDirEntry(int idx, int &parent);
};

class OutputBuffer {
	public:
		pthread_t thread;
		void enqueue(char* ptr);
		OutputBuffer(char* outputFileName);
		virtual ~OutputBuffer();
		char* outputFN;

		void start();
		void run();
	private:
		pthread_mutex_t lock;
		pthread_cond_t empty;
		int head;
		int tail;
		char **buffer;
		int used[BUFFER_SIZE];
		FILE* outputFD;
};

class MtabWatch {
	public:
		pthread_t thread;
		pthread_mutex_t lock;
		pthread_cond_t modified;

		MtabWatch();
		virtual ~MtabWatch();
		void waitForChange();
		void start();
		void run();
};

char** getmtab(int &count);
void *startScan(void* mount);
void *startThread(void* mount);
void *startPrinter(void* outputBuffer);
void init(char* outputFilename, int watchStart, int watchEnd, char** argv);
void daemonize();
#endif
